package library

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jmoiron/sqlx"
	"vip_video/configx"
	"vip_video/internal"
	"vip_video/models"
)

type AuthLibrary struct {
	db       *sqlx.DB
	token    string
	_logined bool
	config   *configx.Config
	_user    *models.UserModel
	_ctx     *gin.Context
}

var _instance *AuthLibrary

// AuthLibraryInstance 新建 token 对象
func AuthLibraryInstance(db *sqlx.DB) *AuthLibrary {
	if _instance == nil {
		_instance = &AuthLibrary{
			db:       db,
			_logined: false,
			_user:    nil,
		}
	}
	return _instance
}

// Direct 直接登录
func (auth *AuthLibrary) Direct(userId int64) (err error) {
	var user models.UserModel
	err = auth.db.Get(&user, "select id,nickname,mobile,avatar,status,prevtime,logintime from fa_user where id=? limit 1;", userId)
	if err != nil {
		return errors.New("用户不存在")
	}
	ip := auth._ctx.RemoteIP()
	timestamp := internal.NowTimestamp()

	//开启事务
	tx, err := auth.db.Beginx()
	if err != nil {
		return errors.New("系统错误")
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()

	//更新用户
	_, err = tx.NamedExec(
		"update fa_user set prevtime=:prevtime,loginip=:loginip,logintime=:logintime,loginfailure=0",
		map[string]any{
			"prevtime":  user.Logintime,
			"loginip":   ip,
			"logintime": timestamp,
		},
	)
	if err != nil {
		return errors.New("系统错误")
	}
	//设置新的 token
	auth._user = &user

	auth.token = internal.GenerateUUID()
	tokenLibrary := NewTokenLibrary().WithDB(auth.db).WithKey(auth.config.Token.Key).WithUserId(userId)
	tokenLibrary.Set(auth.token)
	auth._logined = true

	return nil
}

func (auth *AuthLibrary) WithConfig(config *configx.Config) *AuthLibrary {
	auth.config = config
	return auth
}

func (auth *AuthLibrary) WithGinCtx(ctx *gin.Context) *AuthLibrary {
	auth._ctx = ctx
	return auth
}

// Register 注册用户
func (auth *AuthLibrary) Register(mobile string, password string, extend map[string]any) (err error) {
	//开启事务
	tx, err := auth.db.Beginx()
	if err != nil {
		return errors.New("系统错误")
	}
	defer func() {
		if err == nil {
			_ = tx.Commit()
		} else {
			_ = tx.Rollback()
		}
	}()
	//检查用户是否存在
	var count int64
	if err = auth.db.Get(&count, "select count(*) from fa_user where mobile=? limit 1;", mobile); err != nil {
		return
	}
	if count > 0 {
		err = errors.New("用户已存在")
		return
	}
	//开始注册
	salt := internal.RandStr(10)
	var registerData = map[string]any{
		"username": mobile,
		"nickname": internal.MaskStr(mobile),
		"password": internal.Md5Password(password, salt),
		"salt":     salt,
		"mobile":   mobile,
		"status":   "normal",
	}

	registerData = internal.MergeMaps(registerData, extend)

	//写入数据库
	result, err := auth.db.NamedExec(
		"insert into fa_user(username,nickname,password,salt,mobile,status) values (:username,:nickname,:password,:salt,:mobile,:status)",
		registerData,
	)
	if err != nil {
		return
	}
	userId, err := result.LastInsertId()
	if err != nil {
		return
	}
	//重新获取一次 user 信息
	var user models.UserModel
	err = auth.db.Get(&user, "select id,nickname,mobile,avatar,status from fa_user where id=? limit 1;", userId)
	if err != nil {
		return
	}
	auth._user = &user
	//生成 token
	auth.token = internal.GenerateUUID()
	tokenLibrary := NewTokenLibrary().
		WithDB(auth.db).
		WithKey(auth.config.Token.Key).
		WithUserId(userId)
	tokenLibrary.Set(auth.token)
	auth._logined = true
	return
}

// GetUserInfo 获取用户信息
func (auth *AuthLibrary) GetUserInfo() gin.H {
	return gin.H{
		"token":    auth.token,
		"id":       auth._user.Id,
		"nickname": auth._user.NickName,
		"mobile":   auth._user.Mobile,
		"avatar":   auth._user.Avatar,
	}
}

// GetUserId 获取用户 id
func (auth *AuthLibrary) GetUserId() int64 {
	return auth._user.Id
}

// GetUserNickName 获取用户昵称
func (auth *AuthLibrary) GetUserNickName() string {
	return auth._user.NickName
}

// Init 初始化授权
func (auth *AuthLibrary) Init(token string) (*AuthLibrary, error) {
	if auth._logined {
		return auth, nil
	}
	userId, err := NewTokenLibrary().WithDB(auth.db).WithKey(auth.config.Token.Key).Get(token)
	if err != nil {
		return nil, err
	}
	if userId <= 0 {
		return nil, errors.New("系统错误")
	}
	//获取用户
	var user models.UserModel
	err = auth.db.Get(
		&user,
		"select id,nickname,mobile,avatar,status,prevtime,logintime from fa_user where id=? limit 1;",
		userId,
	)
	if err != nil {
		return nil, errors.New("用户不存在")
	}
	if user.Status != models.STATUS_NORMAL {
		return nil, errors.New("您已被禁用")
	}
	auth._user = &user
	auth._logined = true
	auth.token = token
	return auth, nil
}
